<?php
/**
 * Created by PhpStorm.
 * User: shutao
 * Date: 2019-01-10
 * Time: 16:34
 */

namespace wechat\help;

use yii\db\Exception;

/*
 * 使用示例
  if (!$config = WeiXinService::weConfigFromAppid($appid)) {
      throw new \Exception('找不到指定公众号');
  }

  $app = WeiXinService::app($config);
  $os = new WechatOpenidScanHelp($app);
  foreach ($os as $key => $appid) { // 请求端口每天限额 500 次
       echo $appid; // 可以使用 WechatOpenidScanHelp 来处理业务逻辑
       print_r($os->userInfo()); // 打印当前会员的基本信息；请求端口每天限制 5000000 次
  }
 */

/**
 * 原因：因为公众号不设置回调地址(即无法在用户关注时获取用户的 openid)，所以我们只能手动获取用户的信息
 * 此类的主要作用是，foreach 时公众号的全部关注用户的 openid;
 * 可以配置 WechatOpenidDbHelp 类，处理业务中断 <br>
 * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140840
 * 使用示例查看当前类文件
 */
class WechatOpenidScanHelp implements \Iterator
{
    /**
     * @var \EasyWeChat\OfficialAccount\Application
     */
    public $app;

    /**
     * @var int 关注该公众号的总用户数
     */
    private $_total = 0;
    /**
     * @var int 拉取的 OPENID 个数，最大值为 10000
     */
    private $_count = 0;
    /**
     * @var array OPENID 的列表，最近关注的用户最先显示
     */
    private $_openids = [];
    /**
     * @var string 拉取列表的最后一个用户的 OPENID
     */
    protected $_next_openid = '';

    // 是否需要向微信服务端请求关注用户列表
    private $_nextRequest = true;

    private $_position = 0;

    /**
     * @var int 请求的次数
     */
    public $request_count = 0;

    /**
     * WechatOpenidScanHelp constructor.
     * @param \EasyWeChat\OfficialAccount\Application $app
     * @param string $_next_openid
     */
    public function __construct($app, $_next_openid = '')
    {
        $this->app = $app;
        $this->_next_openid = $_next_openid;
    }

    /*
1. Before the first iteration of the loop, Iterator::rewind() is called.
2. Before each iteration of the loop, Iterator::valid() is called.
3a. It Iterator::valid() returns false, the loop is terminated.
3b. If Iterator::valid() returns true, Iterator::current() and
Iterator::key() are called.
4. The loop body is evaluated.
5. After each iteration of the loop, Iterator::next() is called and we repeat from step 2 above.
    */
    public function current()
    {
        return $this->_openids[$this->_position];
    }

    public function next()
    {
        ++$this->_position;
    }

    public function key()
    {
        return $this->_position;
    }

    public function valid()
    {
        if (isset($this->_openids[$this->_position])) {
            return true;
        } elseif ($this->_nextRequest) {
            $this->nextOpenidList();
        }
        return isset($this->_openids[$this->_position]);
    }

    public function rewind()
    {
        if ($this->_nextRequest) {
            $this->nextOpenidList();
        }
    }

    /*
     * Array
    (
        [total] => 2
        [count] => 2
        [data] => Array
            (
                [openid] => Array
                    (
                        [0] => oNyvw03tFXufFI0zZf5aZi8I6EQg
                        [1] => oNyvw01F8rkEdAkV8TKc0-6CKYl3
                    )

            )

        [next_openid] => oNyvw01F8rkEdAkV8TKc0-6CKYl3
    )
    或者
    Array
(
    [total] => 2
    [count] => 0
    [next_openid] =>
)
     */
    /**
     * 获取用户列表，每次获取 10000 个
     * @throws
     */
    public function nextOpenidList()
    {
        $this->_position = 0;
        $this->request_count++;
        $data = $this->requestData();
        if (isset($data['errcode'])) {
            throw new Exception($data['errmsg'], $data['errcode']);
        }

        $this->_total = $data['total'];
        if ($this->_count = $data['count']) {
            $this->_openids = $data['data']['openid'];
            $this->_next_openid = $data['next_openid'];
            $this->_nextRequest = $this->_total > $this->_count;
        } else {
            $this->_openids = [];
            $this->_next_openid = '';
            $this->_nextRequest = false;
        }
    }

    protected function requestData()
    {
        return $this->app->user->list($this->_next_openid);
    }

    public function getOpenids()
    {
        if ($this->_openids) {
            return $this->_openids;
        } elseif ($this->_nextRequest) {
            $this->nextOpenidList();
        }
        return $this->_openids;
    }

    /**
     * 获取当前用户的基本信息
     * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140839
     * @return array
     * @throws \Exception
     */
    public function userInfo()
    {
        $data = $this->app->user->get($this->current());
        if (isset($data['errcode'])) {
            throw new \Exception($data['errmsg'], $data['errcode']);
        }
        return $data;
    }
}